package novel.manager.service.utils;

import novel.manager.pojo.spider.NovelSiteEnum;
import org.dom4j.Document;
import org.dom4j.Element;
import org.dom4j.io.SAXReader;

import java.io.*;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

public final class NovelSpiderUtil {
	//小说抓取要素的map形式为元素组成的map(NovelSiteEnum,subMap)
	private  static  Map<NovelSiteEnum, Map<String, String>> SpiderRuleXML2MAP = new HashMap<>();
	private  static  Map<NovelSiteEnum, Map<String, String>> NovelListHtmlUrlXML2MAP = new HashMap<>();
	//jvm加载时执行，只执行一次
	static { 
		/**读取小说抓取要素配置文件*/
		SpiderRuleXML2MAP=xml2map("Spider-Rule.xml");
		/**读取小说网站HtmlUrl*/
		NovelListHtmlUrlXML2MAP=xml2map("NovelListHtmlUrl.xml");
	}
	private NovelSpiderUtil() {}
	
	@SuppressWarnings("unchecked")
	/**读取小说抓取要素配置文件：xml2map*/
	public static Map<NovelSiteEnum, Map<String, String>> xml2map(String string) {
		SAXReader reader = new SAXReader();
		Map<NovelSiteEnum, Map<String, String>> XML2MAP = new HashMap<>();
		try {
			//读取小说抓取要素配置文件
/*			URL url = NovelSpiderUtil.class.getClassLoader().getResource(string);
			System.out.println("url:"+url);
			//睡一会观察路径是否读取成功
			Thread.sleep(3_000);
			File file = new File(url.getPath());*/

			Document doc = reader.read(NovelSpiderUtil.class.getClassLoader().getResourceAsStream(string));
			Element root = doc.getRootElement();
			List<Element> sites = root.elements("site");
			for (Element site : sites) {
				List<Element> subs = site.elements();
				//把每个元素转为key/value形式并存放到map(Name,TextTrim)
				Map<String, String> subMap = new HashMap<>();
				for (Element sub : subs) {
					String name = sub.getName();
					String text = sub.getTextTrim();
					subMap.put(name, text);
				}
				//多本小说抓取要素map形式的map(NovelSiteEnum,subMap)
				XML2MAP.put(NovelSiteEnum.getEnumByUrl(subMap.get("url")), subMap);
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		return XML2MAP;
	}
	public static void inputstreamtofile(InputStream ins,File file) {
		try {
			OutputStream os = new FileOutputStream(file);
			int bytesRead = 0;
			byte[] buffer = new byte[8192];
			while ((bytesRead = ins.read(buffer, 0, 8192)) != -1) {
				os.write(buffer, 0, bytesRead);
			}
			os.close();
			ins.close();
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
	/**
	 * 拿到对应网站的解析规则的map形式
	 */
	public static Map<String, String> getSpiderRuleMapByNovelSiteEnum(NovelSiteEnum novelSiteEnum) {
		return SpiderRuleXML2MAP.get(novelSiteEnum);
	}	
	
	/**
	 * 拿到对应小说网站HtmlUrl的map形式
	 */
	public static Map<String, String> getNovelListHtmlUrlMapByNovelSiteEnum(NovelSiteEnum novelSiteEnum) {
		return NovelListHtmlUrlXML2MAP.get(novelSiteEnum);
	}	
	/**
	 * 多个文件合并为一个文件，合并规则：按文件名分割排序
	 * @param path 基础目录，该根目录下的所有文本文件都会被合并到 mergeToFile
	 * @param mergeToFile 被合并的文本文件，这个参数可以为null,合并后的文件保存在path/merge.txt
	 * @param deleteThisFile 是否删除章节子文件
	 */
	public static void multiFileMerge(String path, String mergeToFile, boolean deleteThisFile) {
		//合并后的文件路径
		mergeToFile = mergeToFile == null ? path + "/merge.txt" : mergeToFile;
		//获取指定目录下的所有后缀为.txt的文件
		File[] files = new File(path).listFiles(new FilenameFilter() {
			@Override
			public boolean accept(File dir, String name) {
				return name.endsWith(".txt");
			}
		});
		//合并规则：按文件名分割排序
		Arrays.sort(files, new Comparator<File>() {
			@Override
			public int compare(File o1, File o2) {
				int o1Index = Integer.parseInt(o1.getName().split("\\-")[0]);
				int o2Index = Integer.parseInt(o2.getName().split("\\-")[0]);
				if (o1Index > o2Index) {
					return 1;
				} else if (o1Index == o2Index){
					return 0;
				} else {
					return -1;
				}
			}
		});
		PrintWriter out = null;
		BufferedReader bufr=null ;
		try {
			//创建字符打印流
			out = new PrintWriter(new File(mergeToFile), "UTF-8");
			for (File file : files) {
				//使用缓存流读取被合并的文件到内存：BufferedReader对应BufferedWriter
				bufr = new BufferedReader(new InputStreamReader(new FileInputStream(file), "UTF-8"));	
				String line = null;
				//因为打印流需要String参数，逐行转为String：A String containing the contents of the line, not including any line-termination characters, or null if the end of the stream has been reached 
				while ((line = bufr.readLine()) != null) {
					//逐行下载到合并文件，指导最后一行为null
					out.println(line);
				}
				/**一般来说 Java file.delete失败 有以下几个原因 
				1.看看是否被别的进程引用，手工删除试试(删除不了就是被别的进程占用)
				2.file是文件夹 并且不为空，有别的文件夹或文件， 
				3.极有可能自己前面没有关闭此文件的流(我遇到的情况)*/
				//先关闭读取流再删除，因为该文件还在被使用时不会被删除
				bufr.close();
				//删除章节子文件
				if (deleteThisFile) {
					System.out.println("deleting.....");
					System.out.println("file:"+file);
					file.delete();
				}
			}
		} catch (IOException e1) {
			throw new RuntimeException(e1);
		} finally {
			out.close();
		}
	}
	
	/**
	 * 格式器：String2int,获取书籍的状态
	 */
	public static int getNovelStatus(String status) {
		if (status.contains("连载")) {
			return 1;
		} else if (status.contains("完结") || status.contains("完成") || status.contains("完本")) {
			return 2;
		} else {
			throw new RuntimeException ("不支持的书籍状态：" + status);
		}
	}
	
	/**
	 * 格式器：String2Date，获取日期
	 */
	public static Date getDate(String dateStr, String pattern) throws ParseException {
		if ("MM-dd".equals(pattern)) {
			pattern = "yyyy-MM-dd";
			dateStr = getDateField(Calendar.YEAR) + "-" + dateStr;
		}
		SimpleDateFormat sdf = new SimpleDateFormat(pattern);
		Date date = sdf.parse(dateStr);
		return date;
	}
	
	/**
	 * 获取本时刻的字符量
	 */
	public static String getDateField(int field) {
		//Calendar cal = new GregorianCalendar()
		Calendar cal = new GregorianCalendar();
		return cal.get(field) + "";
	}
}
